Popular Searches
Popular Course Categories
Popular Courses

What is State Management?

What is State Management?

Flutter State Management

What is State Management in Flutter?

State management is the process of storing, changing, sharing, and updating the data that controls what appears on the screen of a Flutter application. In simple terms, state is the data that the UI needs in order to display the correct screen at any moment.

Flutter follows a declarative UI approach. Instead of directly modifying an existing UI element, you change the application's state and Flutter rebuilds the appropriate part of the UI to reflect that state.


1. What is State?

State is any data that can change while an application is running and can affect the UI.

For example, consider a counter application:

int counter = 0;

When the user presses a button, the value changes:

counter = counter + 1;

The displayed number is dependent on this value, so counter is a piece of state.

Examples of State

  • Counter value
  • Selected checkbox
  • Selected tab
  • Text entered into a form
  • Login status
  • Shopping cart items
  • Selected theme
  • List of products
  • Loading status
  • Error messages
  • API response data
  • User preferences

2. Simple Definition

You can remember state management with this simple formula:

State changes
     ↓
UI needs to reflect the change
     ↓
Flutter rebuilds the required UI
     ↓
User sees updated information

3. Why Do We Need State Management?

Small applications can manage state locally inside widgets. As an application becomes larger, state may need to be shared between multiple widgets and screens.

Without an appropriate state-management approach, an application can become difficult to maintain because the same data may be passed through many widgets or duplicated in multiple places.

Example Without Proper State Management

HomeScreen
   ↓
Dashboard
   ↓
ProductScreen
   ↓
CartScreen
   ↓
CheckoutScreen

If every screen needs access to the same shopping cart, manually passing the cart through every widget can become cumbersome.

With Shared State

         Cart State
        /     |     \
       ↓      ↓      ↓
   Product  Cart   Checkout
    Screen  Screen  Screen

A shared state-management approach can make application state easier to access and update.


4. StatelessWidget vs StatefulWidget

Understanding the difference between StatelessWidget and StatefulWidget is an important foundation for learning state management.

StatelessWidget StatefulWidget
Does not maintain mutable state in a State object Works with a separate State object that can hold mutable state
Useful when UI depends only on input values Useful when UI changes during the widget's lifetime
No setState() Can use setState() to trigger a rebuild
Examples: static labels and icons Examples: counters, toggles, interactive forms

5. Basic StatefulWidget Example

import 'package:flutter/material.dart';

class CounterScreen extends StatefulWidget {
  const CounterScreen({super.key});

  @override
  State createState() => _CounterScreenState();
}

class _CounterScreenState extends State {
  int counter = 0;

  void incrementCounter() {
    setState(() {
      counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Counter'),
      ),
      body: Center(
        child: Text(
          '$counter',
          style: const TextStyle(fontSize: 40),
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: incrementCounter,
        child: const Icon(Icons.add),
      ),
    );
  }
}

6. What is setState()?

setState() is a built-in Flutter mechanism used by a State object to tell Flutter that its internal state has changed and that the widget should be rebuilt.

setState(() {
  counter++;
});

When the state changes without calling setState(), Flutter may not rebuild the widget to reflect the changed value.


7. What Happens When setState() is Called?

User taps button
       ↓
Event handler runs
       ↓
State changes
       ↓
setState() is called
       ↓
Flutter schedules rebuild
       ↓
build() runs again
       ↓
Updated UI appears

8. What Happens Without setState()?

Consider:

void incrementCounter() {
  counter++;
}

The variable may change internally, but Flutter has not been explicitly notified. Therefore, the UI may continue showing the old value.

Correct approach:

void incrementCounter() {
  setState(() {
    counter++;
  });
}

9. Types of State

Flutter documentation commonly discusses two conceptual types of state: ephemeral state and application state.

9.1 Ephemeral State

Ephemeral state, also called local or UI state, is state that can be contained neatly inside a single widget.

Examples:

  • Current selected tab
  • Whether a password is visible
  • Animation progress
  • Current checkbox selection
  • Temporary form input
class Example extends StatefulWidget {
  const Example({super.key});

  @override
  State createState() => _ExampleState();
}

class _ExampleState extends State {
  bool isVisible = false;

  @override
  Widget build(BuildContext context) {
    return Switch(
      value: isVisible,
      onChanged: (value) {
        setState(() {
          isVisible = value;
        });
      },
    );
  }
}

9.2 Application State

Application state, also called shared state, is state that needs to be accessed by multiple parts of the application or may need to persist across parts of the user experience.

Examples:

  • Logged-in user information
  • Shopping cart
  • User preferences
  • Notifications
  • Application settings
  • Shared API data

10. Local State vs Shared State

Local State Shared State
Used by one widget or a small UI section Used by multiple widgets or screens
Usually simple to manage May require a dedicated state-management approach
Example: selected tab Example: logged-in user
Often uses setState() Can use ChangeNotifier, Provider, or other approaches

11. Parent-Managed State

Sometimes the state of a child widget is better managed by its parent. The parent stores the state and passes the current value and callback to the child.

class ParentWidget extends StatefulWidget {
  const ParentWidget({super.key});

  @override
  State createState() => _ParentWidgetState();
}

class _ParentWidgetState extends State {
  bool isSelected = false;

  @override
  Widget build(BuildContext context) {
    return ChildWidget(
      isSelected: isSelected,
      onChanged: (value) {
        setState(() {
          isSelected = value;
        });
      },
    );
  }
}

class ChildWidget extends StatelessWidget {
  final bool isSelected;
  final ValueChanged onChanged;

  const ChildWidget({
    super.key,
    required this.isSelected,
    required this.onChanged,
  });

  @override
  Widget build(BuildContext context) {
    return Checkbox(
      value: isSelected,
      onChanged: (value) {
        onChanged(value ?? false);
      },
    );
  }
}

This pattern keeps the source of truth in the parent while the child displays and modifies the value through a callback.


12. State Flow in Flutter

         State
           ↓
      Widget Build
           ↓
           UI
           ↓
    User Interaction
           ↓
    State Modification
           ↓
         State
           ↓
      UI Rebuilds

13. Declarative UI and State

Flutter uses a declarative approach to UI development:

UI = f(State)

This means the UI can be thought of as a function of the current state.

bool isLoggedIn = true;

if (isLoggedIn) {
  return const HomeScreen();
} else {
  return const LoginScreen();
}

If isLoggedIn changes, the UI reflects the new state automatically.


14. Why State Management Becomes Important in Large Apps

As applications grow, several widgets may need access to the same information.

Product Screen
      ↓
Add Product
      ↓
Shopping Cart State
      ↓
Cart Screen
      ↓
Checkout Screen
      ↓
Order Screen

If the cart state is needed by many screens, manually passing it through multiple widget constructors can become cumbersome.


15. Common State Management Approaches in Flutter

Built-in Approaches

  • setState()
  • ValueNotifier
  • InheritedNotifier
  • InheritedWidget
  • InheritedModel
  • ChangeNotifier

Community Packages and Architectures

  • Provider
  • Riverpod
  • Bloc / Cubit
  • Redux
  • GetX
  • Other community solutions

16. setState()

setState() is the simplest built-in approach for local, widget-specific state.

class Counter extends StatefulWidget {
  const Counter({super.key});

  @override
  State createState() => _CounterState();
}

class _CounterState extends State {
  int count = 0;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: [
        Text('$count'),
        ElevatedButton(
          onPressed: () {
            setState(() {
              count++;
            });
          },
          child: const Text('Increment'),
        ),
      ],
    );
  }
}

17. ValueNotifier

ValueNotifier is a Flutter-provided mechanism for holding a value and notifying listeners when it changes.

final counter = ValueNotifier(0);

counter.value++;
counter.value = 10;

A widget can listen to the value using ValueListenableBuilder:

ValueListenableBuilder(
  valueListenable: counter,
  builder: (context, value, child) {
    return Text(
      '$value',
      style: const TextStyle(fontSize: 30),
    );
  },
)

18. InheritedWidget

InheritedWidget is a lower-level Flutter mechanism for making data available to descendant widgets in the widget tree.

class AppData extends InheritedWidget {
  final String username;

  const AppData({
    super.key,
    required this.username,
    required super.child,
  });

  static AppData of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType()!;
  }

  @override
  bool updateShouldNotify(AppData oldWidget) {
    return username != oldWidget.username;
  }
}

19. ChangeNotifier

ChangeNotifier is a Flutter SDK class that allows an object to notify listeners when its data changes.

class CounterModel extends ChangeNotifier {
  int count = 0;

  void increment() {
    count++;
    notifyListeners();
  }
}

Calling notifyListeners() tells listening widgets that the state has changed and they should rebuild.


20. Provider

Provider is a community package that builds on Flutter's widget and notification mechanisms to make shared state easier to expose and consume.

flutter pub add provider

A common Provider setup uses ChangeNotifier, ChangeNotifierProvider, and Consumer.

Provider Example

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

class CounterProvider extends ChangeNotifier {
  int count = 0;

  void increment() {
    count++;
    notifyListeners();
  }
}

void main() {
  runApp(
    ChangeNotifierProvider(
      create: (_) => CounterProvider(),
      child: const MyApp(),
    ),
  );
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      home: Scaffold(
        body: Center(
          child: Consumer(
            builder: (context, counter, child) {
              return Text(
                '${counter.count}',
                style: const TextStyle(fontSize: 30),
              );
            },
          ),
        ),
        floatingActionButton: Builder(
          builder: (context) {
            return FloatingActionButton(
              onPressed: () {
                context.read().increment();
              },
              child: const Icon(Icons.add),
            );
          },
        ),
      ),
    );
  }
}

21. Riverpod

Riverpod is another community state-management solution. It provides mechanisms for declaring and consuming application state and is commonly used when applications require more structured dependency and state management.

The exact APIs depend on the Riverpod version and package configuration, so developers should follow the current package documentation when implementing it.


22. Bloc and Cubit

Bloc and Cubit are popular approaches for organizing application state around predictable state changes.

UI
 ↓
Cubit / Bloc
 ↓
Repository
 ↓
API / Firebase / Database

This approach is useful for applications where business logic and state transitions need to be clearly separated from the UI.


23. State Management with API Calls

State management becomes especially useful when an application communicates with an API. An API request commonly has several states:

Initial → Loading → Success → Data Available

Or:

Initial → Loading → Error → Error Message

Example State Variables

bool isLoading = false;
String? errorMessage;
List products = [];

24. Loading, Success, Error and Empty States

State Example UI
Initial Welcome or initial screen
Loading Progress indicator
Success Display retrieved data
Empty No data available message
Error Error message and retry option

25. Example ViewModel with ChangeNotifier

class ProductViewModel extends ChangeNotifier {
  bool isLoading = false;
  String? error;
  List products = [];

  Future loadProducts() async {
    isLoading = true;
    error = null;
    notifyListeners();

    try {
      await Future.delayed(const Duration(seconds: 2));
      products = ['Laptop', 'Phone', 'Tablet'];
    } catch (e) {
      error = 'Unable to load products';
    } finally {
      isLoading = false;
      notifyListeners();
    }
  }
}

26. State Management with Firebase

State management is particularly useful when working with Firebase because Firebase operations are asynchronous and application data can change over time.

Firebase Authentication → Authentication State → UI
Cloud Firestore → Task/Product Data → State Management → Flutter UI

27. Authentication State Example

StreamBuilder(
  stream: FirebaseAuth.instance.authStateChanges(),
  builder: (context, snapshot) {
    if (snapshot.connectionState == ConnectionState.waiting) {
      return const CircularProgressIndicator();
    }

    if (snapshot.hasData) {
      return const HomeScreen();
    }

    return const LoginScreen();
  },
)

28. State Management and Widget Rebuilds

Old State
   ↓
State Change
   ↓
Notification / setState
   ↓
Widget Rebuild
   ↓
New UI

29. State Management and Separation of Responsibilities

A scalable Flutter application should avoid placing all application logic inside widgets.

UI Layer
   ↓
ViewModel / State Manager
   ↓
Repository / Service
   ↓
API / Firebase / Database

30. Example Application Architecture

lib/
├── main.dart
├── models/
│   └── product.dart
├── views/
│   ├── home_screen.dart
│   └── product_screen.dart
├── viewmodels/
│   └── product_viewmodel.dart
├── services/
│   └── api_service.dart
└── repositories/
    └── product_repository.dart

31. State Management Best Practices

  • Use setState() for simple local state
  • Do not introduce a complex state-management package for every small widget
  • Move shared application state into an appropriate shared-state solution
  • Keep business logic outside large UI widgets
  • Keep API and Firebase operations in services or repositories
  • Represent loading, success, error, and empty states clearly
  • Avoid unnecessary rebuilds
  • Keep one clear source of truth for important shared data
  • Dispose controllers, streams, and other resources when required
  • Choose an approach that matches the project's complexity and team needs

32. Common State Management Mistakes

  • Using setState() for complicated global application state
  • Creating duplicate copies of the same application data
  • Putting API logic directly inside large widgets
  • Forgetting to notify listeners when using ChangeNotifier
  • Calling setState() after a widget has been disposed
  • Not handling loading and error states
  • Rebuilding a large widget tree unnecessarily
  • Using a package without understanding the underlying state flow
  • Keeping unrelated state in one large state-management class

33. How to Choose a State Management Approach?

Requirement Possible Approach
Small widget-specific state setState()
Simple observable value ValueNotifier
Shared state with simple architecture Provider / ChangeNotifier
More structured application state Riverpod, Bloc/Cubit, or another suitable approach
Very simple application Built-in Flutter state mechanisms

34. Practical Example: Shopping Cart State

class CartState extends ChangeNotifier {
  final List items = [];

  void addItem(String item) {
    items.add(item);
    notifyListeners();
  }

  void removeItem(String item) {
    items.remove(item);
    notifyListeners();
  }

  int get itemCount => items.length;
}

35. Practical Example: Theme State

class ThemeState extends ChangeNotifier {
  bool isDarkMode = false;

  void toggleTheme() {
    isDarkMode = !isDarkMode;
    notifyListeners();
  }
}

36. Practical Example: Login State

class AuthState extends ChangeNotifier {
  bool isLoggedIn = false;

  void login() {
    isLoggedIn = true;
    notifyListeners();
  }

  void logout() {
    isLoggedIn = false;
    notifyListeners();
  }
}

37. State Management Lifecycle

1. Create State
      ↓
2. Display State
      ↓
3. User / System Event
      ↓
4. Modify State
      ↓
5. Notify Flutter / Listeners
      ↓
6. Rebuild UI
      ↓
7. Display Updated State

38. State Management in a Real Application

Consider a food delivery application:

Authentication State → Home Screen → Restaurant State
        ↓
Cart State → Order State → Payment State

Each state has its own responsibility rather than placing all application data into a single massive state object.


39. State Management and Performance

Good state management helps control which parts of the UI need to rebuild when data changes.

Product List  → unchanged → no rebuild
Cart Count    → changed   → rebuild only required UI

40. State Management and Asynchronous Data

Applications frequently receive data asynchronously from REST APIs, Firebase, Cloud Firestore, local databases, streams, and WebSockets.

Request Started → Loading = true
      ↓
Request Completed → Success / Error
      ↓
Loading = false → UI Updates

41. State Management with StreamBuilder

StreamBuilder(
  stream: counterStream,
  builder: (context, snapshot) {
    if (!snapshot.hasData) {
      return const CircularProgressIndicator();
    }

    return Text('${snapshot.data}');
  },
)

42. State Management vs UI Management

State Management UI Management
Stores application data Displays application data
Changes data based on events Builds widgets based on current data
Handles business/application state Handles presentation
Can communicate with repositories and services Uses widgets to render information

43. Key Concepts to Remember

  • State — Data that can change and affect the UI
  • State Management — The process of organizing and updating that data
  • setState — Built-in mechanism for notifying Flutter about local state changes
  • StatefulWidget — A widget that works with a mutable State object
  • Ephemeral State — Local state usually contained within a widget
  • App State — Shared state used across multiple parts of an application
  • ChangeNotifier — A Flutter class that can notify listeners when data changes
  • Provider — A community package that simplifies exposing and consuming shared state
  • ViewModel — A layer that holds presentation state and related logic

44. Interview Questions

Q1. What is state management in Flutter? State management is the process of managing data that can change during the lifetime of an application and ensuring that the UI reflects those changes.

Q2. What is state? State is data required to build the correct UI at a particular moment and can change over time.

Q3. What is setState()? setState() is a method used inside a State object to notify Flutter that its state has changed and the widget should be rebuilt.

Q4. What is the difference between StatelessWidget and StatefulWidget? A StatelessWidget does not maintain mutable state through a State object, while a StatefulWidget works with a separate State object that can hold mutable state and trigger rebuilds.

Q5. What is ephemeral state? Ephemeral state is local state that can usually be contained within a single widget, such as a selected tab or temporary UI value.

Q6. What is application state? Application state is shared state that may be needed by multiple parts of an application, such as authentication information, shopping cart data, or user preferences.

Q7. What is ChangeNotifier? ChangeNotifier is a Flutter SDK class that allows an object to notify listeners when its state changes.

Q8. What does notifyListeners() do? It notifies listeners that the data has changed so that listening widgets can rebuild and display the new state.

Q9. When should setState() be used? It is particularly suitable for simple, local, widget-specific or ephemeral state.

Q10. Why is state management important in large applications? Large applications often have shared data used by multiple widgets and screens. State management helps organize that data and its updates so the application remains easier to maintain.


45. Quick Revision

Concept Key Point
State Data that can change and affect the UI
State Management Organizing and updating changing data
setState() Notify Flutter about local state changes
ChangeNotifier Notify listeners when state changes
Provider A community solution for sharing and consuming state
App State Shared application data
Ephemeral State Local widget-specific data

46. Learning Outcome

After completing this topic, you should understand:

  • What state means in Flutter
  • Why state management is required
  • How StatefulWidget and setState() work
  • The difference between ephemeral and application state
  • How state can be shared between widgets
  • How approaches such as ChangeNotifier, Provider, and other state-management solutions can be used as applications become more complex

47. Summary

State management is one of the most important concepts in Flutter development. State represents data that can change and affect the user interface. For simple local state, Flutter's StatefulWidget and setState() are often sufficient. As an application grows, shared-state mechanisms and state-management packages can help organize data and application logic.

The main idea to remember is:

Change State
     ↓
Notify / Trigger Rebuild
     ↓
Flutter Rebuilds UI
     ↓
User Sees Current State

Flutter provides several built-in state-management mechanisms and supports many community solutions. The appropriate approach depends on the size, architecture, requirements, and team preferences of the application.

whatsapp